#include "client.h"

// 发送一个完整的 TLV 包
int send_tlv(int sock_fd, int type, const char* value, int length) {
    tlv_header_t header;
    header.type = type; 
    header.length = length;

    // 1. 发送头部
    if (send_all(sock_fd, &header, sizeof(header)) < 0) {
        perror("send header failed");
        return -1;
    }
    // 2. 发送值 (如果存在)
    if (length > 0) {
        if (send_all(sock_fd, value, length) < 0) {
            perror("send value failed");
            return -1;
        }
    }
    return 0;
}

// 确保发送所有数据 (处理TCP短写)
int send_all(int sock_fd, const void* buffer, int length) {
    int total_sent = 0;
    while (total_sent < length) {
        ssize_t sent = send(sock_fd, (char*)buffer + total_sent, length - total_sent, 0);
        if (sent < 0) return -1;
        total_sent += (int)sent;
    }
    return total_sent;
}

// 确保接收所有数据 (处理TCP短读)
int recv_all(int sock_fd, void* buffer, int length) {
    int total_received = 0;
    while (total_received < length) {
        ssize_t received = recv(sock_fd, (char*)buffer + total_received, length - total_received, 0);
        if (received <= 0) return (int)received; // 错误或连接关闭
        total_received += (int)received;
    }
    return total_received;
}

// 响应处理
int receive_and_process_response(int sockfd) {
    tlv_header_t header;

    // 1. 读取 TLV 头部
    if (recv_all(sockfd, &header, sizeof(header)) <= 0) {
        fprintf(stderr, "与服务器的连接中断。\n");
        return -1; // 或者做其他错误处理
    }


    // 2. 根据 Length 分配内存并读取 Value
    char* value = NULL;
    if (header.length > 0) {
        value = (char*)malloc(header.length + 1);
        if (value == NULL) {
            perror("malloc failed");
            return -1;
        }
        if (recv_all(sockfd, value, header.length) <= 0) {
            fprintf(stderr, "与服务器的连接中断。\n");
            free(value);
            return -1;
        }
        value[header.length] = '\0'; // 确保字符串以 null 结尾
    }

    // 3. 根据 Type 处理 Value
    switch (header.type) {
    case RESP_OK:
        break;
    case RESP_ERROR:
        fprintf(stderr, "服务器错误: %s\n", value ? value : "无详细信息");
        break;
    case RESP_LS_RESULT:
    case RESP_PWD_RESULT:
        if (value) {
            printf("%s", value); // ls的结果可能包含换行符，所以不用加 \n
        }
        break;
    case RESP_SUCCESS_MR:
    case RESP_FAILURE_MR:
        break;
    default:
        fprintf(stderr, "收到未知的服务器响应类型: %d\n", header.type);
        break;
    }

    if (value) {
        free(value);
    }
    return 0;
}

// 下载函数
int receive_file_content(int sockfd, char *local_filename) {
    // 创建存储目录
    if (mkdir(DEFAULT_STORAGE_PATH, 0775) != 0) {
        // 判断是否是目录存在导致的创建失败
        if (errno != EEXIST) {
            // 目录不存在的情况
            perror("创建默认存储目录失败");
            return -1;
        }
    }

    // 创建文件
    char file_path[1024] = { 0 };
    snprintf(file_path, sizeof(file_path), "%s/%s", DEFAULT_STORAGE_PATH, local_filename);
    int fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0664);
    ERROR_CHECK(fd, -1, "open failed");

    printf("准备接收文件，将保存为 %s\n", file_path);

    while (1) {
        tlv_header_t header;

        // 1. 读取 TLV 头部
        if (recv_all(sockfd, &header, sizeof(header)) <= 0) {
            fprintf(stderr, "与服务端的连接中断！\n");
            close(fd);
            return -1;
        }

        // 判断是否是错误响应
        if (header.type == RESP_ERROR) {
            fprintf(stderr, "服务器返回错误。\n");
            // 接收并打印错误
            if (header.length > 0) {
                char err_msg[4096] = { 0 };
                int len_to_read = header.length < (int)sizeof(err_msg) - 1 ?
                    header.length : sizeof(err_msg) - 1;
                recv_all(sockfd, err_msg, len_to_read);
                fprintf(stderr, "错误信息: %s\n", err_msg);
            }

            close(fd);
            remove(file_path);
            return -1;
        }

        // 判断是否是文件数据
        if (header.type != RESP_FILE_DATA) {
            // 非预期的包类型
            fprintf(stderr, "协议错误: 收到非文件数据包，类型为 %d\n", header.type);
            close(fd);
            remove(file_path);
            return -1;
        }

        // 如果 length 为0，表示文件接收接收
        if (header.length == 0) {
            printf("文件接收完毕。\n");
            break;
        }

        // 读取 value 并写入文件
        char buffer[4096] = { 0 };
        int bytes_to_read = header.length;
        while (bytes_to_read > 0) {
            int chunk_size = bytes_to_read > (int)sizeof(buffer) ?
                sizeof(buffer) : bytes_to_read;

            if (recv_all(sockfd, buffer, chunk_size) <= 0) {
                fprintf(stderr, "连接中断！\n");
                close(fd);
                return -1;
            }

            write(fd, buffer, chunk_size);
            bytes_to_read -= chunk_size;
        }
    }

    close(fd);
    return 0;
}

// 上传响应处理
int wait_for_response_type(int sockfd) {
    tlv_header_t tlv_header;

    if (recv_all(sockfd, &tlv_header, sizeof(tlv_header)) <= 0) {
        fprintf(stderr, "与服务器的连接中断。\n");
        return -1; // 或者做其他错误处理
    }

    // 如果tlv包有数据，就将数据读出来丢弃。
    char buffer[4096] = { 0 };
    int bytes_to_read = tlv_header.length;

    while (bytes_to_read > 0) {
        int chunk_size = bytes_to_read > (int)sizeof(buffer) ?
            sizeof(buffer) : bytes_to_read;

        int ret = recv_all(sockfd, buffer, chunk_size);
        if (ret <= 0) {
            fprintf(stderr, "在丢弃数据时连接中断。\n");
            return -1; // 发生错误，返回-1
        }

        bytes_to_read -= chunk_size;
    }

    return tlv_header.type;

}
